package obecto.tween
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;
	
	import obecto.utility.DictionaryUtil;
	import obecto.utility.EnterFrameBeacon;

	[Event(name="tweensUpdated", type="flash.events.Event")]
	public class TweensManager extends EventDispatcher
	{
		private static var _instance : TweensManager;
		public static function get instance() : TweensManager
		{
			if (_instance == null)
			{
				_instance = new TweensManager();	
			}
			return _instance;
		}
		
		private var tweens : Dictionary;
		
		public function TweensManager()
		{
			super();
			
			if (_instance != null)
			{
				throw new Error("Attempt to create another instance of TweensManager.");	
			}
			
			_instance = this;
			
			tweens = new Dictionary();
			EnterFrameBeacon.instance.addEventListener(Event.ENTER_FRAME, handleEnterFrame);
		}
		
		public function doTween(tween : AbstractTween) : void
		{
			if (tween.duration > 0)
			{
				tweens[tween] = tween;
			}
			else
			{
				for (var key : Object in tween.tweeningProperties)
				{
					tween.target[key] = tween.tweeningProperties[key];
				}
				
				tween.tweenUpdateDelegate();
				tween.tweenFinishedDelegate();
			}
		}
		
		public function stopTweensForTarget(target : Object) : void
		{
			for each (var tween : AbstractTween in tweens)
			{
				if (tween.target == target)
				{
					for (var key : String in tween.tweeningProperties)
					{
						delete tween.tweeningProperties[key];
					}
					
					if (DictionaryUtil.getCount(tween.tweeningProperties) > 0)
					{
						delete tweens[DictionaryUtil.getKey(tween, tweens)];
					}
				}
			}
		}
		
		public function stopTweensForTargets(targets : Array) : void
		{
			for each (var target : Object in targets)
			{
				stopTweensForTarget(target);
			}
		}
		
		public function stopTweensFor(target : Object, tweeningProperties : Dictionary) : void
		{
			for each (var tween : AbstractTween in tweens)
			{
				if (tween.target == target)
				{
					for (var propertyKey : String in tweeningProperties)
					{
						if (DictionaryUtil.containsKey(propertyKey, tween.tweeningProperties))
						{
							delete tween.tweeningProperties[propertyKey];
						}
					}
					
					if (DictionaryUtil.getCount(tween.tweeningProperties) > 0)
					{
						delete tweens[DictionaryUtil.getKey(tween, tweens)];
					}
				}
			}
		}
		
		public function stopTween(tween : AbstractTween) : void
		{
			delete tweens[tween];
		}
		
		public function hasTweensForTarget(target : Object) : Boolean
		{
			var result : Boolean = false;
			for each (var tween : AbstractTween in tweens)
			{
				if (tween.target == target)
				{
					result = true;
					break;
				}
			}
			return result;
		}
		
		private function handleEnterFrame(event : Event) : void
		{
			var tween : AbstractTween;
			for (var key : Object in tweens)
			{
				tween = AbstractTween(tweens[key]);
				tween.update();
				
				if (tween.finished)
				{
					delete tweens[key];
				}
			}
			
			dispatchEvent(new Event("tweensUpdated"));
		}
	}
}